package com.lyf.boot.modules.system.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyf.boot.base.system.entity.SysUser;
import com.lyf.boot.base.system.entity.SysUserRole;
import com.lyf.boot.core.model.IdDto;
import com.lyf.boot.core.model.PageInfo;
import com.lyf.boot.exception.ServiceException;
import com.lyf.boot.modules.system.dao.SysDeptDao;
import com.lyf.boot.modules.system.dao.SysUserDao;
import com.lyf.boot.modules.system.dao.SysUserRoleDao;
import com.lyf.boot.modules.system.entity.dto.CheckSysUserDto;
import com.lyf.boot.modules.system.entity.dto.SysUserDto;
import com.lyf.boot.modules.system.entity.dto.SysUserPageDto;
import com.lyf.boot.modules.system.entity.vo.SysUserRoleVo;
import com.lyf.boot.modules.system.entity.vo.SysUserVo;
import com.lyf.boot.modules.system.service.ISysUserService;
import com.lyf.boot.utils.MapstructUtil;
import com.lyf.boot.utils.StreamUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Luyufan
 * @date 2023/7/5 18:52
 */
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements ISysUserService {

    private final SysUserDao sysUserDao;

    private final SysDeptDao sysDeptDao;

    private final SysUserRoleDao sysUserRoleDao;

    @Override
    public PageInfo<SysUserVo> getSysUserPage(SysUserPageDto dto) {
        Page<SysUserVo> page = dto.of();
        if(null != dto.getDeptId()){
            List<Long> deptIds = sysDeptDao.selectAllSubDeptId(dto.getDeptId());
            dto.setDeptIds(deptIds);
        }
        PageInfo<SysUserVo> userPage = PageInfo.build(sysUserDao.selectSysUserPage(page, dto));
        if(userPage.isEmpty()){
            return userPage;
        }
        List<SysUserVo> sysUserList = userPage.getRecords();
        //查询用户的角色
        List<Long> userIds = sysUserList.stream().map(SysUserVo::getUserId).collect(Collectors.toList());
        List<SysUserRoleVo> userRoles = sysUserRoleDao.selectSysUserRoleByUserIds(userIds);
        if(CollUtil.isEmpty(userRoles)){
            return userPage;
        }
        Map<Long, List<SysUserRoleVo>> userRoleGroup = userRoles.stream().collect(Collectors.groupingBy(SysUserRoleVo::getUserId));
        sysUserList.forEach(sysUser -> sysUser.setRoles(userRoleGroup.get(sysUser.getUserId())));
        return userPage;
    }

    @Override
    public SysUserVo getSysUserInfo(Long userId) {
        SysUserVo sysUserVo = sysUserDao.selectSysUserById(userId);
        Assert.notNull(sysUserVo, "用户已被删除");
        List<SysUserRoleVo> userRoles = sysUserRoleDao.selectSysUserRoleByUserIds(CollUtil.toList(userId));
        sysUserVo.setRoles(userRoles);
        sysUserVo.setRoleIds(StreamUtil.toList(userRoles, SysUserRoleVo::getRoleId));
        return sysUserVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSysUser(SysUserDto dto) {
        SysUser sysUser = MapstructUtil.convert(dto, SysUser.class);
        String password = "123456";
        sysUser.setPassword(BCrypt.hashpw(password));
        sysUserDao.insert(sysUser);
        List<Long> roleIds = dto.getRoleIds();
        if(CollUtil.isEmpty(roleIds)){
            return;
        }
        List<SysUserRole> userRoles = new ArrayList<>();
        roleIds.forEach(roleId -> userRoles.add(new SysUserRole(sysUser.getUserId(), roleId)));
        if(CollUtil.isNotEmpty(userRoles)){
            sysUserRoleDao.batchInsert(userRoles);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSysUser(SysUserDto dto) {
        Long userId = dto.getUserId();
        SysUser sysUserDb = sysUserDao.selectById(userId);
        Assert.notNull(sysUserDb, "用户不存在");
        sysUserDao.update(null, Wrappers.<SysUser>lambdaUpdate()
                .set(SysUser::getRealName, dto.getRealName())
                .set(SysUser::getNickName, dto.getNickName())
                .set(SysUser::getPhoneNumber, dto.getPhoneNumber())
                .set(SysUser::getEmail, dto.getEmail())
                .set(SysUser::getStatus, dto.getStatus())
                .set(SysUser::getDeptId, dto.getDeptId())
                .set(SysUser::getGender, dto.getGender())
                .set(SysUser::getRemark, dto.getRemark())
                .eq(SysUser::getUserId, userId));
        //清除用户的角色
        sysUserRoleDao.delete(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, userId));
        List<Long> roleIds = dto.getRoleIds();
        if(CollUtil.isEmpty(roleIds)){
            return;
        }
        List<SysUserRole> userRoles = new ArrayList<>();
        roleIds.forEach(roleId -> userRoles.add(new SysUserRole(userId, roleId)));
        sysUserRoleDao.batchInsert(userRoles);
    }

    @Override
    public void deleteSysUser(List<Long> ids) {
        sysUserDao.deleteByIds(ids);
    }

    @Override
    public void resetPassword(IdDto dto) {
        String password = "123456";
        password = BCrypt.hashpw(password);
        sysUserDao.update(null, Wrappers.<SysUser>lambdaUpdate()
                .set(SysUser::getPassword, password).eq(SysUser::getUserId, dto.getId()));
    }

    @Override
    public Boolean checkSysUserExist(CheckSysUserDto dto) {
        if(BeanUtil.isEmpty(dto)){
            throw new ServiceException("校验属性不能为空");
        }
        return sysUserDao.exists(Wrappers.<SysUser>lambdaQuery()
                .eq(StrUtil.isNotBlank(dto.getUsername()), SysUser::getUsername, dto.getUsername())
                .eq(StrUtil.isNotBlank(dto.getPhoneNumber()), SysUser::getPhoneNumber, dto.getPhoneNumber())
                .eq(StrUtil.isNotBlank(dto.getEmail()), SysUser::getEmail, dto.getEmail()));
    }
}
